/*
 *only support for "exact division"
 *
 *
 * */



#include <stdlib.h>
#include <stdio.h>
#include "slave.h"
#include "2d5p_aceMesh.h"
#include "task.h"
#include "dma.h"

#define alpha_d 0.0876
#define beta_d  0.0765

__thread_local volatile unsigned long get_reply,put_reply;

//core region
__thread_local_fix double slave[2][BLKX][BLKY];
//__thread_local double A_lhs[BLKX][BLKY];
//__thread_local double A_rhs[BLKX][BLKY];
//up and down shade region
__thread_local double A_us[BLKY];
__thread_local double A_ds[BLKY];
//left and right shade  region
__thread_local double A_ls[BLKX];
__thread_local double A_rs[BLKX];
//Record the logical information of the last time executed task.
__thread_local int dest,src,i,j,k,s_iter,s_starti,s_endi,s_startj,s_endj,s_startk,s_endk;
//__thread_local dma_desc dma_d;
//__thread_local int last_iter,last_starti,last_startj;

#ifdef _PROFILING
__thread_local volatile unsigned long start,end;
__thread_local volatile unsigned long dma_start,dma_end;
__thread_local volatile unsigned long comp_start,comp_end;
__thread_local int core_id=0;
//__thread_local int myreuse=0;
extern unsigned long slave_comp_count[64];
extern unsigned long slave_dma_count[64];
extern unsigned long slave_count[64];
//extern unsigned long slave_reuse_count[64];
extern unsigned long slave_up[64];
extern unsigned long slave_up1[64]; //only halo
extern unsigned long slave_down[64];

unsigned long rtc_()
{
  unsigned long rpcc;
  asm volatile("rcsr  %0,4":"=r"(rpcc));
  return rpcc;
}
#endif

extern double A[2][SIZEX][SIZEY];

void stencil_core(targs* args)
{
   int bsize,stride,tsize; 
   int tmp[8],*buf;

   int tileno[2];
   int varno[2],reuse[2];
   int lhs_no,rhs_no;
   int dma_get_count=0;
   int dma_put_count=0;

   s_iter = args->iter;
   s_starti = args->starti;
   s_endi = args->endi;
   s_startj = args->startj;
   s_endj = args->endj;
   //buf=&(tmp[0]);
   //simd_load(*((intv8*)buf),args);
   //s_iter=tmp[4],s_starti=tmp[0],s_endi=tmp[1],s_startj=tmp[2],s_endj=tmp[3];
   dest = (s_iter) % 2 ; 
   src = 1 - dest;
                   
   lhs_no=0;
   rhs_no=1;
#ifdef _PROFILING
   core_id=athread_get_id(-1);
   slave_up[core_id]+=BLKX*BLKY+2*(BLKX+BLKY);
   slave_up1[core_id]+=2*BLKX;
   slave_down[core_id]+=BLKX*BLKY;
   dma_start=rtc_();
#endif
     get_reply = 0;
     //1.0 update inner-core data
     stride = (SIZEY-BLKY)*8;
     tsize = BLKX*BLKY*8;
     bsize = BLKY*8;
     athread_get(PE_MODE,&A[src][s_starti][s_startj]
                   , &slave[rhs_no][0][0]
                   , tsize, (void*)&get_reply
                   , 0, stride, bsize);
     //1.1 update up and down shade data    
     athread_get(PE_MODE,&A[src][s_starti-1][s_startj],&A_us[0],BLKY*8,(void*)&get_reply,0,0,0); 
     athread_get(PE_MODE,&A[src][s_endi][s_startj], &A_ds[0],BLKY*8,(void*)&get_reply,0,0,0);
     //1.2 update left and right shade data
     stride = (SIZEY-1)*8;
     tsize = BLKX*8;
     bsize = 8;
     athread_get(PE_MODE,&A[src][s_starti][s_startj-1]
                   , &A_ls[0]
                   , tsize,(void*)&get_reply
                   , 0, stride, bsize);
     athread_get(PE_MODE,&A[src][s_starti][s_endj]
                   , &A_rs[0]
                   , tsize,(void*)&get_reply
                   , 0, stride, bsize);  
     while(get_reply != 5);
#ifdef _ON_CHIP_TRANSFER
//TODO:how to enable this??
     for(i=s_starti;i<s_endi;++i)
     {
        A_ls[i-s_starti]=A[src][i][s_startj-1];
        A_rs[i-s_starti]=A[src][i][s_endj];
     }
#endif

#ifdef _PROFILING
   dma_end=rtc_();
   slave_dma_count[core_id]+=((dma_end-dma_start));
   comp_start=rtc_();
#endif
     //2.compute core data
     for(i = 1; i < BLKX-1; i++)
       for(j = 1; j < BLKY-1; j++)
        {
          slave[lhs_no][i][j] = alpha_d * (slave[rhs_no][i][j]) + \
                     beta_d * (slave[rhs_no][i-1][j] + slave[rhs_no][i+1][j] +\
                     slave[rhs_no][i][j-1] + slave[rhs_no][i][j+1]);
        }
     //3.1compute up_left_point
     slave[lhs_no][0][0] = alpha_d * (slave[rhs_no][0][0]) + \
                   beta_d * (A_us[0] + slave[rhs_no][1][0] +\
                   A_ls[0] + slave[rhs_no][0][1]); 
     //3.2compute up_right_point
     slave[lhs_no][BLKX-1][0] =   alpha_d * (slave[rhs_no][BLKX-1][0]) +\
                     beta_d * (slave[rhs_no][BLKX-2][0] + A_ds[0] +\
                     A_ls[BLKX-1] + slave[rhs_no][BLKX-1][1]);
     //3.3compute up_right_point
     slave[lhs_no][0][BLKY-1] = alpha_d * (slave[rhs_no][0][BLKY-1]) + \
                     beta_d * (A_us[BLKY-1] +\
                     slave[rhs_no][1][BLKY-1] +\
                     slave[rhs_no][0][BLKX-2] + A_rs[0]);
     //3.4compute down_right_point
     slave[lhs_no][BLKX-1][BLKY-1] = alpha_d * \
                     (slave[rhs_no][BLKX-1][BLKY-1]) + \
                     beta_d * (slave[rhs_no][BLKX-2][BLKY-1] + \
                     A_ds[BLKY-1] + \
                     slave[rhs_no][BLKX-1][BLKY-2] + \
                     A_rs[BLKX-1]);
     //4.1 compute up and down line of j dimensional  change 
     for(j = 1;j < BLKY-1; ++j)
     {
       slave[lhs_no][0][j] = alpha_d * (slave[rhs_no][0][j]) + \
                     beta_d * (A_us[j] + slave[rhs_no][1][j] +\
                     slave[rhs_no][0][j-1] + slave[rhs_no][0][j+1]);
       slave[lhs_no][BLKX-1][j] = alpha_d * (slave[rhs_no][BLKX-1][j]) + \
                     beta_d * (slave[rhs_no][BLKX-2][j] + A_ds[j] +\
                     slave[rhs_no][BLKX-1][j-1] + slave[rhs_no][BLKX-1][j+1]);
     }
     //4.2 compute left and right line of i dimensional change
     for(i = 1;i < BLKX-1; ++i)
     {
        slave[lhs_no][i][0] = alpha_d * (slave[rhs_no][i][0]) + \
                     beta_d * (slave[rhs_no][i-1][0] + slave[rhs_no][i+1][0] +\
                     A_ls[i] + slave[rhs_no][i][1]);
        slave[lhs_no][i][BLKY-1] = alpha_d * (slave[rhs_no][i][BLKY-1]) + \
                     beta_d * (slave[rhs_no][i-1][BLKY-1] + slave[rhs_no][i+1][BLKY-1] +\
                     slave[rhs_no][i][BLKY-2] + A_rs[i]);
     }
#ifdef _PROFILING
   comp_end=rtc_();
   slave_comp_count[core_id]+=(comp_end-comp_start);
   dma_start=rtc_();
#endif
     //5:write back
     put_reply=0;
     bsize=(BLKY)*8;
     stride=(SIZEY-(BLKY))*8;  //stride: from blocktail to blockhead
     tsize= bsize*(BLKX);
     athread_put(PE_MODE,&slave[lhs_no][0][0]
                , &A[dest][s_starti][s_startj]
                ,tsize,(void*)&put_reply,stride,bsize);
     while(put_reply!=1);
#ifdef _PROFILING
   dma_end=rtc_();
   slave_dma_count[core_id]+=((dma_end-dma_start));
#endif
}
